flag_remove: Option<Vec<String>>,
flag_index: Option<String>,
flag_verbose: bool,
+ flag_list: bool,
}
pub const USAGE: &'static str = "
-h, --help Print this message
-a, --add LOGIN Login of a user to add as an owner
-r, --remove LOGIN Login of a user to remove as an owner
+ -l, --list List owners of a crate
--index INDEX Registry index to modify owners for
--token TOKEN API token to use when authenticating
-v, --verbose Use verbose output
pub fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
shell.set_verbose(options.flag_verbose);
let root = try!(find_root_manifest_for_cwd(None));
- try!(ops::modify_owners(&root, shell,
- options.arg_crate,
- options.flag_token,
- options.flag_index,
- options.flag_add,
- options.flag_remove).map_err(|e| {
+ let opts = ops::OwnersOptions {
+ krate: options.arg_crate,
+ token: options.flag_token,
+ index: options.flag_index,
+ to_add: options.flag_add,
+ to_remove: options.flag_remove,
+ list: options.flag_list,
+ };
+ try!(ops::modify_owners(&root, shell, &opts).map_err(|e| {
CliError::from_boxed(e, 101)
}));
Ok(None)
pub use self::cargo_package::package;
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{registry_login, http_proxy, http_handle};
-pub use self::registry::{modify_owners, yank};
+pub use self::registry::{modify_owners, yank, OwnersOptions};
pub use self::cargo_fetch::{fetch};
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{resolve_pkg, resolve_with_previous};
config::set_config(&config, config::Global, "registry", config::Table(map))
}
+pub struct OwnersOptions {
+ pub krate: Option<String>,
+ pub token: Option<String>,
+ pub index: Option<String>,
+ pub to_add: Option<Vec<String>>,
+ pub to_remove: Option<Vec<String>>,
+ pub list: bool,
+}
+
pub fn modify_owners(manifest_path: &Path,
shell: &mut MultiShell,
- krate: Option<String>,
- token: Option<String>,
- index: Option<String>,
- to_add: Option<Vec<String>>,
- to_remove: Option<Vec<String>>) -> CargoResult<()> {
- let name = match krate {
- Some(name) => name,
+ opts: &OwnersOptions) -> CargoResult<()> {
+ let name = match opts.krate {
+ Some(ref name) => name.clone(),
None => {
let mut src = try!(PathSource::for_path(&manifest_path.dir_path()));
try!(src.update());
}
};
- let (mut registry, _) = try!(registry(shell, token, index));
+ let (mut registry, _) = try!(registry(shell, opts.token.clone(),
+ opts.index.clone()));
- match to_add {
- Some(v) => {
+ match opts.to_add {
+ Some(ref v) => {
let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
try!(shell.status("Owner", format!("adding `{:#}` to `{}`", v, name)));
try!(registry.add_owners(name.as_slice(), v.as_slice()).map_err(|e| {
None => {}
}
- match to_remove {
- Some(v) => {
+ match opts.to_remove {
+ Some(ref v) => {
let v = v.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
try!(shell.status("Owner", format!("removing `{:#}` from `{}`",
v, name)));
None => {}
}
+ if opts.list {
+ let owners = try!(registry.list_owners(name.as_slice()).map_err(|e| {
+ human(format!("failed to list owners: {}", e))
+ }));
+ for owner in owners.iter() {
+ print!("{}", owner.login);
+ match (owner.name.as_ref(), owner.email.as_ref()) {
+ (Some(name), Some(email)) => println!(" ({} <{}>)", name, email),
+ (Some(s), None) |
+ (None, Some(s)) => println!(" ({})", s),
+ (None, None) => println!(""),
+ }
+ }
+ }
+
Ok(())
}
use std::result;
use curl::http;
+use curl::http::handle::{Put, Get, Delete, Method, Request};
use serialize::json;
pub struct Registry {
pub target: Option<String>,
}
+#[deriving(Decodable)]
+pub struct User {
+ pub id: uint,
+ pub login: String,
+ pub avatar: String,
+ pub email: Option<String>,
+ pub name: Option<String>,
+}
+
#[deriving(Decodable)] struct R { ok: bool }
#[deriving(Decodable)] struct ApiErrorList { errors: Vec<ApiError> }
#[deriving(Decodable)] struct ApiError { detail: String }
#[deriving(Encodable)] struct OwnersReq<'a> { users: &'a [&'a str] }
+#[deriving(Decodable)] struct Users { users: Vec<User> }
impl Registry {
pub fn new(host: String, token: String) -> Registry {
Ok(())
}
+ pub fn list_owners(&mut self, krate: &str) -> Result<Vec<User>> {
+ let body = try!(self.get(format!("/crates/{}/owners", krate)));
+ Ok(json::decode::<Users>(body.as_slice()).unwrap().users)
+ }
+
pub fn publish(&mut self, krate: &NewCrate, tarball: &Path) -> Result<()> {
let json = json::encode(krate);
// Prepare the body. The format of the upload request is:
}
fn put(&mut self, path: String, b: &[u8]) -> Result<String> {
- handle(self.handle.put(format!("{}/api/v1{}", self.host, path), b)
- .header("Authorization", self.token.as_slice())
- .header("Accept", "application/json")
- .content_type("application/json")
- .exec())
+ self.req(path, Some(b), Put)
+ }
+
+ fn get(&mut self, path: String) -> Result<String> {
+ self.req(path, None, Get)
}
fn delete(&mut self, path: String, b: Option<&[u8]>) -> Result<String> {
- let mut req = self.handle.delete(format!("{}/api/v1{}", self.host, path))
- .header("Authorization", self.token.as_slice())
- .header("Accept", "application/json")
- .content_type("application/json");
- match b {
+ self.req(path, b, Delete)
+ }
+
+ fn req(&mut self, path: String, body: Option<&[u8]>,
+ method: Method) -> Result<String> {
+ let mut req = Request::new(&mut self.handle, method)
+ .uri(format!("{}/api/v1{}", self.host, path))
+ .header("Authorization", self.token.as_slice())
+ .header("Accept", "application/json")
+ .content_type("application/json");
+ match body {
Some(b) => req = req.body(b),
None => {}
}